package wiki.xsx.core.pdf.doc;

import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.pdfbox.contentstream.PDContentStream;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdfparser.PDFStreamParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import wiki.xsx.core.pdf.util.XEasyPdfFileUtil;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * @program x-easypdf
 * @description:
 * @author: lee
 * @create: 2023/07/02 12:45
 */
public class Mains {
    public static void main(String[] args) throws Exception {
        String sourcePath = "/Users/ligang/Desktop/1.pdf";
        String outputPath = "/Users/ligang/Desktop/2.pdf";
        File file = new File(sourcePath);
        PDDocument load = PDDocument.load(file);
        PDPageTree pages = load.getPages();
        // 遍历pdfBox页面树
        for (PDPage page : pages) {
            replaceText(page,load,"i","kk");
        }
        try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(XEasyPdfFileUtil.createDirectories(Paths.get(outputPath))))) {
           load.save(outputStream);
        }
    }
    public static List<Object> replaceText(PDContentStream contentStream, PDDocument document, String witch, String replace) throws Exception			 {
        //得到当前页面的所有的资源
        PDResources resources = contentStream.getResources();
        //解析当前页面，并得到token
        PDFStreamParser parser = new PDFStreamParser(contentStream);
        Object token = parser.parseNextToken();
        List<Object> newTokens = new ArrayList<Object>();
        Map<COSName, PDFont> fontMap = new HashMap<COSName, PDFont>();
        //遇到字体的时候保留起来，写入文本之前一定会设置字体，因此解析文本的时候上一个设置的字体就是当前文本使用的字体
        List<PDFont> souce_fonts = new ArrayList<PDFont>();
        /*
         * 加载字体（虽然我们得到了当前流的字体但是使用encode的时候无法进行编码，
         * 猜测pdfbox并没有加载到相应的字体库绘图文件，所以我们要替换掉对应的字体，
         * 为了方便目前中文全用simsun字体替代）,最好相应的字体加载相应的文件
         * */
        PDFont simSunFont = getSimSunFont(document);
        while (token != null) {
            if (token instanceof Operator) {
                Operator op = (Operator) token;
                // 得到对应的字体
                if ("Tf".equals(op.getName())) {
                    COSName cosName = (COSName) newTokens.get(newTokens.size() - 2);
                    PDFont sourceFont = resources.getFont(cosName);
                    System.out.println(sourceFont.getName());//如果encode异常的时候加入对应的字体
                    souce_fonts.add(resources.getFont(cosName));
                    if((sourceFont.getName().toLowerCase().indexOf("simsun")>-1)||(sourceFont.getName().toLowerCase().indexOf("pingfang")>-1) && fontMap.get(cosName) == null) {
                        fontMap.put(cosName, simSunFont);
                    }
                }
                if ("Tj".equals(op.getName()) || "TJ".equals(op.getName()) || "".equals(op.getName())) {
                    COSString previous = (COSString) newTokens.get(newTokens.size() - 1);
                    PDType0Font pdFont = (PDType0Font) souce_fonts.get(souce_fonts.size() - 1);
                    //得到COSString的字节数组，并用原始字体进行读取转换操作拼接成字符串
                    byte[] bytes = previous.getBytes();
                    InputStream in = new ByteArrayInputStream(bytes);
                    StringBuffer sb = new StringBuffer();
                    while (in.available() > 0) {
                        int code = pdFont.readCode(in);
                        String value = pdFont.toUnicode(code);
                        sb.append(value);
                    }
                    System.out.println("原有字符串：" + sb.toString());
                    //替换文本
                    previous.setValue(simSunFont.encode(sb.toString().replace(witch, replace)));
                    System.out.println(previous);
                } else if ("\"".equals(op.getName())) {
                    // remove the 3 arguments to this operator
                    newTokens.remove(newTokens.size() - 1);
                    newTokens.remove(newTokens.size() - 1);
                    newTokens.remove(newTokens.size() - 1);
                    token = parser.parseNextToken();
                }
            }
            newTokens.add(token);
            token = parser.parseNextToken();
        }
        //统一替换字体资源
        Set<Map.Entry<COSName, PDFont>> entrySet = fontMap.entrySet();
        for (Map.Entry<COSName, PDFont> entry : entrySet) {
            resources.put(entry.getKey(), entry.getValue());
        }
        return newTokens;
    }
    public static PDFont getSimSunFont(PDDocument document) throws IOException {
        String fontPath = "/usr/local/software/work/idea/iuap-apcom-contract/iuap-apcom-contract/src/main/resources/simsun.ttc";

        TrueTypeCollection ttc3 = new TrueTypeCollection(new File(fontPath));
        TrueTypeFont trueTypeFont = ttc3.getFontByName("SimSun");
        PDType0Font sourceFont = PDType0Font.load(document, trueTypeFont, true);
        return sourceFont;
    }
}
